package org.edu.modules.kwgl.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Maps;
import org.edu.common.api.vo.Result;
import org.edu.modules.jxzy.entity.JwKecheng;
import org.edu.modules.jxzy.service.IJwKechengService;
import org.edu.modules.kwgl.api.CommonApi;
import org.edu.modules.kwgl.api.IVeJwJxzyFeignClientService;
import org.edu.modules.kwgl.entity.VeJwBkXuesheng;
import org.edu.modules.kwgl.entity.VeJwChengji;
import org.edu.modules.kwgl.entity.VeJwKaoshi;
import org.edu.modules.kwgl.mapper.VeJwChengjiMapper;
import org.edu.modules.kwgl.service.IVeJwChengjiService;
import org.edu.modules.kwgl.dto.WarningStudentDto;
import org.edu.modules.kwgl.dto.WarningDetailDto;
import org.edu.modules.kwgl.service.IVeJwKaoshiService;
import org.edu.modules.scheduleCommon.dto.BasePageDto;
import org.edu.modules.scheduleCommon.dto.PassRateStatistics;
import org.edu.modules.scheduleCommon.dto.ScoreAnalysis;
import org.edu.modules.scheduleCommon.entity.VeBaseBanji;
import org.edu.modules.scheduleCommon.mapper.VeBaseBanjiMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.stream.Collectors;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;



/**
 * @Description: 成绩
 * @Author: jeecg-boot
 * @Date:   2021-05-12
 * @Version: V1.0
 */
@Service
public class VeJwChengjiServiceImpl extends ServiceImpl<VeJwChengjiMapper, VeJwChengji> implements IVeJwChengjiService {

    @Autowired
    private VeJwChengjiMapper veJwChengjiMapper;
    @Autowired
    private VeBaseBanjiMapper veBaseBanjiMapper;
    @Autowired
    private CommonApi commonApi;
    @Autowired
    private IJwKechengService jwKechengService;
    @Autowired
    private IVeJwKaoshiService jwKaoshiService;
    @Autowired
    private org.edu.modules.kwgl.mapper.VeJwCjyjMapper veJwCjyjMapper;

    @Override
    public IPage<VeJwChengji> pageDto(BasePageDto page, Wrapper queryWrapper) {
        return baseMapper.pageDto(page, queryWrapper);
    }

    @Override
    public List<VeJwChengji> getByCondition(VeJwChengji condition) {
        QueryWrapper queryWrapper=new QueryWrapper<VeJwBkXuesheng>()
                //默认只筛选不及格的学生
                .eq("SFJG",0);
        if(condition.getKcid()!=null){
            queryWrapper.eq("kcId",condition.getKcid());
        }
        if(condition.getStuid()!=null){
            queryWrapper.eq("stuId",condition.getStuid());
        }
        if(condition.getXm()!=null){
            queryWrapper .eq("XM",condition.getXm());
        }
        if(condition.getGradeid()!=null){
            queryWrapper.eq("gradeId",condition.getGradeid());
        }
        if(condition.getSemid()!=null){
            queryWrapper.eq("semId",condition.getSemid());
        }
        if(condition.getSpecid()!=null){
            queryWrapper.eq("specId",condition.getSpecid());
        }

        return baseMapper.selectList(queryWrapper);
    }

    @Override
    public BigDecimal caleJgl(VeJwChengji param, Integer falid) {
        // 获取总人数
        BigDecimal totalCount = new BigDecimal(this.getCountByParam(param, falid, true));
        // 如果总人数为0，及格率也为0
        if(totalCount.equals(BigDecimal.ZERO)){
            return BigDecimal.ZERO;
        }

        // 获取及格人数
        BigDecimal jgCount = new BigDecimal(this.getCountByParam(param, falid, false));
        // 及格率，单位"%"
        BigDecimal jgl = jgCount.divide(totalCount, 4, BigDecimal.ROUND_DOWN).multiply(new BigDecimal(100));
        return jgl;
    }

    @Override
    public Map<String, JSONObject> queryAllJgl() {
        // 返回的值
        Map<String, JSONObject> data = Maps.newHashMap();
        // 查询所有专业组的所有学期的考试成绩数据
        List<JSONObject> result = getBaseMapper().selectAllCjData();
        for (JSONObject item : result){
            item.put("jgl", this.caleJgl(item.getInteger("jgs"), item.getInteger("zs")));
            data.put(item.getInteger("falid") + "_" + item.getInteger("semid"), item);
        }
        return data;
    }

    @Override
    public List<ScoreAnalysis> scoreAnalysis(Integer falId, Integer specId, Integer gradeId, Integer semId, Integer kcId) {
        return veJwChengjiMapper.scoreAnalysis(falId, specId, gradeId, semId, kcId);
    }

    @Override
    public List<PassRateStatistics> passRateStatistics(Integer falId, Integer specId, Integer gradeId, Integer semId, Integer xzbId) {
        return veJwChengjiMapper.passRateStatistics(falId, specId, gradeId, semId, xzbId);
    }

    @Override
    public IPage<WarningStudentDto> getWarningStudentsByCredits(VeJwChengji veJwChengji, Integer pageNo, Integer pageSize) {
        Page<WarningStudentDto> page = new Page<>(pageNo, pageSize);
        LambdaQueryWrapper<VeJwChengji> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(VeJwChengji::getSfjg, 0);
        if (veJwChengji.getFalid() != null) {
            queryWrapper.eq(VeJwChengji::getFalid, veJwChengji.getFalid());
        }
        if (veJwChengji.getSpecid() != null) {
            queryWrapper.eq(VeJwChengji::getSpecid, veJwChengji.getSpecid());
        }
        if (veJwChengji.getGradeid() != null) {
            queryWrapper.eq(VeJwChengji::getGradeid, veJwChengji.getGradeid());
        }
        if (veJwChengji.getSemid() != null) {
            queryWrapper.eq(VeJwChengji::getSemid, veJwChengji.getSemid());
        }
        List<VeJwChengji> failedRecords = this.list(queryWrapper);



        Map<String, WarningStudentDto> studentMap = new HashMap<>();
        for (VeJwChengji record : failedRecords) {
            String key = record.getXh();
            if (!studentMap.containsKey(key)) {
                WarningStudentDto dto = new WarningStudentDto();
                dto.setXh(record.getXh());
                dto.setXm(record.getXm());
                dto.setBj(record.getXzbid() != null ? getBanjiName(record.getXzbid()) : "");
                dto.setZy(record.getSpecid() != null ? getSpecialtyName(record.getSpecid()) : "");
                dto.setWarningType(1);
                dto.setWarningValue(BigDecimal.ZERO);
                dto.setTotalFailedCredits(BigDecimal.ZERO);
                dto.setFailedSubjectsCount(0);
                studentMap.put(key, dto);
            }
            WarningStudentDto dto = studentMap.get(key);
            BigDecimal credit = getCourseCredit(record.getKcid());
            dto.setTotalFailedCredits(dto.getTotalFailedCredits().add(credit));
            dto.setFailedSubjectsCount(dto.getFailedSubjectsCount() + 1);
        }
        List<WarningStudentDto> resultList = studentMap.values().stream()
                .filter(dto -> dto.getTotalFailedCredits().compareTo(new BigDecimal("30")) > 0)
                .peek(dto -> dto.setWarningValue(dto.getTotalFailedCredits()))
                .sorted((a, b) -> b.getTotalFailedCredits().compareTo(a.getTotalFailedCredits()))
                .collect(Collectors.toList());
        int start = (pageNo - 1) * pageSize;
        int end = Math.min(start + pageSize, resultList.size());
        List<WarningStudentDto> pageRecords = resultList.subList(start, end);
        page.setRecords(pageRecords);
        page.setTotal(resultList.size());
        page.setCurrent(pageNo);
        page.setSize(pageSize);
        return page;
    }

    @Override
    public IPage<WarningStudentDto> getWarningStudentsBySubjects(VeJwChengji veJwChengji, Integer pageNo, Integer pageSize) {
        Page<WarningStudentDto> page = new Page<>(pageNo, pageSize);
        LambdaQueryWrapper<VeJwChengji> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(VeJwChengji::getSfjg, 0);
        if (veJwChengji.getFalid() != null) {
            queryWrapper.eq(VeJwChengji::getFalid, veJwChengji.getFalid());
        }
        if (veJwChengji.getSpecid() != null) {
            queryWrapper.eq(VeJwChengji::getSpecid, veJwChengji.getSpecid());
        }
        if (veJwChengji.getGradeid() != null) {
            queryWrapper.eq(VeJwChengji::getGradeid, veJwChengji.getGradeid());
        }
        if (veJwChengji.getSemid() != null) {
            queryWrapper.eq(VeJwChengji::getSemid, veJwChengji.getSemid());
        }
        List<VeJwChengji> failedRecords = this.list(queryWrapper);


        Map<String, WarningStudentDto> studentMap = new HashMap<>();
        for (VeJwChengji record : failedRecords) {
            String key = record.getXh();
            if (!studentMap.containsKey(key)) {
                WarningStudentDto dto = new WarningStudentDto();
                dto.setXh(record.getXh());
                dto.setXm(record.getXm());
                dto.setBj(record.getXzbid() != null ? getBanjiName(record.getXzbid()) : "");
                dto.setZy(record.getSpecid() != null ? getSpecialtyName(record.getSpecid()) : "");
                dto.setWarningType(2);
                dto.setWarningValue(BigDecimal.ZERO);
                dto.setTotalFailedCredits(BigDecimal.ZERO);
                dto.setFailedSubjectsCount(0);
                studentMap.put(key, dto);
            }
            WarningStudentDto dto = studentMap.get(key);
            BigDecimal credit = getCourseCredit(record.getKcid());
            dto.setTotalFailedCredits(dto.getTotalFailedCredits().add(credit));
            dto.setFailedSubjectsCount(dto.getFailedSubjectsCount() + 1);
        }
        List<WarningStudentDto> resultList = studentMap.values().stream()
                .filter(dto -> dto.getFailedSubjectsCount() >= 7)
                .peek(dto -> dto.setWarningValue(new BigDecimal(dto.getFailedSubjectsCount())))
                .sorted((a, b) -> Integer.compare(b.getFailedSubjectsCount(), a.getFailedSubjectsCount()))
                .collect(Collectors.toList());
        int start = (pageNo - 1) * pageSize;
        int end = Math.min(start + pageSize, resultList.size());
        List<WarningStudentDto> pageRecords = resultList.subList(start, end);
        page.setRecords(pageRecords);
        page.setTotal(resultList.size());
        page.setCurrent(pageNo);
        page.setSize(pageSize);
        return page;
    }

    @Override
    public List<WarningDetailDto> getWarningDetail(VeJwChengji veJwChengji) {
        LambdaQueryWrapper<VeJwChengji> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(VeJwChengji::getSfjg, 0);
        queryWrapper.eq(VeJwChengji::getXh, veJwChengji.getXh());
        if (veJwChengji.getFalid() != null) {
            queryWrapper.eq(VeJwChengji::getFalid, veJwChengji.getFalid());
        }
        if (veJwChengji.getSpecid() != null) {
            queryWrapper.eq(VeJwChengji::getSpecid, veJwChengji.getSpecid());
        }
        if (veJwChengji.getGradeid() != null) {
            queryWrapper.eq(VeJwChengji::getGradeid, veJwChengji.getGradeid());
        }
        if (veJwChengji.getSemid() != null) {
            queryWrapper.eq(VeJwChengji::getSemid, veJwChengji.getSemid());
        }
        queryWrapper.orderByAsc(VeJwChengji::getKcid);
        List<VeJwChengji> failedRecords = this.list(queryWrapper);
        List<WarningDetailDto> resultList = new ArrayList<>();
        for (VeJwChengji record : failedRecords) {
            WarningDetailDto dto = new WarningDetailDto();
            dto.setXh(record.getXh());
            dto.setXm(record.getXm());
            dto.setBj(record.getXzbid() != null ? getBanjiName(record.getXzbid()) : "");
            dto.setZy(record.getSpecid() != null ? getSpecialtyName(record.getSpecid()) : "");
            dto.setKcmc(getCourseName(record.getKcid()));
            dto.setKcxf(getCourseCredit(record.getKcid()));
            dto.setKccj(record.getKccj());
            dto.setSfjg(record.getSfjg());
            dto.setKsrq(getKaoshiDate(record.getKsid()));
            dto.setSem(getSemesterName(record.getSemid()));
            resultList.add(dto);
        }
        return resultList;
    }

    // 辅助方法：获取班级名称
    private String getBanjiName(Integer banjiId) {
        VeBaseBanji byId = veBaseBanjiMapper.findById(banjiId);
        if (byId == null){
            return null;
        }
        return byId.getNjmc();
    }

    // 辅助方法：获取专业名称
    private String getSpecialtyName(Integer specialtyId) {
        Result<JSONObject> result = commonApi.querySpecialtyById(org.edu.modules.jxgz.api.CommonApi.COMMON_TOKEN_KEY, specialtyId);
        if (result.getResult().get("zymc") == null){
            return null;
        }
        return result.getResult().get("zymc").toString();
    }

    // 辅助方法：获取课程名称
    private String getCourseName(Integer courseId) {
        JwKecheng byId = jwKechengService.getById(courseId);
        if (byId == null){
            return null;
        }
        return byId.getKcmc();
    }

    // 辅助方法：获取课程学分
    private BigDecimal getCourseCredit(Integer courseId) {
        JwKecheng byId = jwKechengService.getById(courseId);
        if (byId == null){
            return null;
        }
        return byId.getXf();
    }

    // 辅助方法：获取考试日期
    private String getKaoshiDate(Integer kaoshiId) {
        VeJwKaoshi byKcid = jwKaoshiService.getByKcid(kaoshiId);
        if (byKcid == null){
            return null;
        }
        return byKcid.getKsrq();
    }

    // 辅助方法：获取学期名称
    private String getSemesterName(Integer semesterId) {
        Result<List<JSONObject>> listResult = commonApi.querySemesterList(org.edu.modules.jxgz.api.CommonApi.COMMON_TOKEN_KEY);
        String name = null;
        for (JSONObject jsonObject : listResult.getResult()) {
            if (jsonObject.get("id").equals(semesterId)){
                if (jsonObject.get("xqmc") != null){
                    name = jsonObject.get("xqmc").toString();
                    break;
                }
            }
        }
        return name;
    }

    /**
     * 计算及格率
     * @param jgs
     * @param zs
     * @return
     */
    private BigDecimal caleJgl(Integer jgs, Integer zs){
        if(zs.equals(0)){
            return new BigDecimal("0.00");
        }
        BigDecimal totalCount = new BigDecimal(zs);
        BigDecimal jgCount = new BigDecimal(jgs);

        return jgCount.divide(totalCount, 4, BigDecimal.ROUND_DOWN)
                .divide(new BigDecimal("0.01"), 2, BigDecimal.ROUND_DOWN);
    }

    /**
     * 获取人数
     * @param param 参数
     * @param falid 专业
     * @param isQueryTotal 是否查询总人数
     * @return
     */
    private int getCountByParam(VeJwChengji param, Integer falid, Boolean isQueryTotal){
        LambdaQueryWrapper<VeJwChengji> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(VeJwChengji::getSemid, param.getSemid());
        wrapper.eq(VeJwChengji::getFalid, falid);
        // 年级
        if(param.getGradeid() != null){
            wrapper.eq(VeJwChengji::getGradeid, param.getGradeid());
        }
        // 专业
        if(param.getSpecid() != null){
            wrapper.eq(VeJwChengji::getSpecid, param.getSpecid());
        }
        // 班级
        if(param.getXzbid() != null){
            wrapper.eq(VeJwChengji::getXzbid, param.getXzbid());
        }

        // 状态：及格
        if(!isQueryTotal){
            wrapper.eq(VeJwChengji::getSfjg, 1);
        }
        return this.count(wrapper);
    }
}
